#include "resman.h"
#include "exceptions.h"

Resman *Resman::global = 0;


Resman::Resman()
{
}

Resman::~Resman()
{
	//dtor
}

Resman *Resman::getResman()
{
	if ( !global )
	{
		global = new Resman();
	}

	return global;
}

i32 Resman::HASH ( string text )
{
	u32 result = 0;

	for ( u32 c = 0; c < text.length(); c++ )
	{
		result += text[c] * 432 * c;
	}

	return result;
}

Resource *Resman::GET ( string text )
{
	i32 hash = HASH ( text );

	for ( u32 c = 0; c < _resources.size(); c++ )
	{
		if ( _resources[c]->hash == hash ) {
			return _resources[c];
		}
	}

	LOGP2 ( "RESMAN: No resource named [%s]", text.c_str() );
	return 0;
}

i32 Resman::LoadStatic ( string f_name, string res_name, i32 non_alfa )
{
	SDL_Surface *temp;
	SDL_Surface *sprite = SDL_LoadBMP ( f_name.c_str() );
	Sprite n_spr;

	if ( sprite == NULL )
	{
		LOGP2 ( "Error while loading %s", f_name.c_str() );
		EXCEX ( 0x01, "Sprite loading failed !" );
		return ( -1 );
	}

	if ( sprite->format->palette )
	{
		SDL_SetColorKey ( sprite, ( SDL_SRCCOLORKEY | SDL_RLEACCEL ),
						  * ( Uint8 * ) sprite->pixels );
	}

	temp = SDL_DisplayFormat ( sprite );
	SDL_FreeSurface ( sprite );

	if ( temp == NULL )
	{
		LOGP3 ( "Couldn't convert background: %s [%s]", SDL_GetError(), f_name.c_str() );
		EXCEX ( 0x01, "Sprite loading failed !" );
		return ( -1 );
	}

	i32 hash = HASH ( res_name );
	Frame f;
	f.surface[0] = temp;
	n_spr.frames.push_back ( f );
	n_spr.ID = hash;
	Graphics *res_g = new Graphics;
	res_g->hash = hash;
	res_g->org_name = res_name;
	res_g->spr = n_spr;
	_resources.push_back ( res_g );
	LOGP3 ( "Sprite [%s] : [%d] loaded...[OK]", f_name.c_str(), hash );
	return 0;
}


i32 Resman::LoadStaticAnim ( string f_name, string res_name, i32 frames )
{
	SDL_Surface *temp;
	SDL_Surface *sprite;
	Sprite n_spr;
	i32 hash = HASH ( res_name );

	if ( frames > 16 )
	{
		EXCEX ( 0x05, "So many frames ? Are you out of youre mind ?" );
	}

	for ( i32 c = 0; c < frames; c++ )
	{
		char buff[100], buff2[100], ext[30];
		u32 dot = f_name.rfind ( "." );
		memcpy ( buff, f_name.c_str(), dot );
		buff[dot] = 0;
		memcpy ( ext, f_name.c_str() + dot, f_name.length() - dot );
		ext[f_name.length() - dot] = 0;
		sprintf ( buff2, "%s%d%s", buff, c, ext );
		//LOGP2("FILE %s",buff2);
		sprite = SDL_LoadBMP ( buff2 );

		if ( sprite == NULL )
		{
			LOGP2 ( "Error while loading %s", buff2 );
			EXCEX ( 0x01, "Sprite loading failed !" );
			return ( -1 );
		}

//		if ( sprite->format->palette )
//		{
//			SDL_SetColorKey ( sprite, ( SDL_SRCCOLORKEY | SDL_RLEACCEL ),
//							  * ( Uint8 * ) sprite->pixels );
//		}
		temp = SDL_DisplayFormat ( sprite );
		SDL_FreeSurface ( sprite );

		if ( temp == NULL )
		{
			LOGP3 ( "Couldn't convert background: %s [%s]", SDL_GetError(), buff2 );
			EXCEX ( 0x01, "Sprite loading failed !" );
			return ( -1 );
		}

		Frame f;
		f.surface[0] = temp;
		n_spr.frames.push_back ( f );
		u32 *pix_data;

		if ( temp->format->BytesPerPixel == 4 )
		{
			for ( i32 c = 0; c < temp->w * temp->h * 4; c += 4 )
			{
				pix_data = ( u32 * ) & ( ( u8 * ) temp->pixels ) [c];
				*pix_data = *pix_data | 0xFF000000;
			}
		}

		if ( c == 0 )
		{
			n_spr.w = temp->w;
			n_spr.h = temp->h;
		}
		else
		{
			if ( ( n_spr.w != ( u32 ) temp->w ) || ( n_spr.h != ( u32 ) temp->h ) )
			{
				EXCEX ( 0x06, "Animation frames have defferent size." );
			}
		}

		//LOGP3 ( "Sprite [%s] : [%d] loaded...[OK]", buff2, hash );
	}

	n_spr.ID = hash;
	Graphics *res_g = new Graphics;
	res_g->hash = hash;
	res_g->org_name = res_name;
	res_g->spr = n_spr;
	_resources.push_back ( res_g );
	return 1;     // number of currently added sprite
}

i32 Resman::LoadLiveObject ( string f_name, string res_name, i32 frames )
{
	LOGP2 ( "Loading game object [%s]...", f_name.c_str() );
	LoadStaticAnim ( f_name, res_name, frames );
	LOGP3 ( "Loading animation completed [%d frames]. Rotating images...%d times", frames, ANGLES );
	SDL_Surface *tmp = 0;
	Graphics *res = ( Graphics * ) GET ( res_name );

	if ( !res )
	{
		EXCEX ( 0xFA, "LoadLiveObject can't find animation in resources" );
	}

	for ( i32 c = 0; c < frames; c++ )
	{
		for ( u32 v = 0; v < ANGLES; v++ )
		{
			double ang = 360 - ( 360 / ANGLES * v );
			tmp = rotozoomSurface ( res->spr.frames[c].surface[0], ang, 1, 1 );
			res->spr.frames[c].surface[v] = tmp;
			//_sprites[v_id].frames[c].surface[v] = tmp;
			u32 *pix_data;
			u32 cl = 0x00FFAEC9;        // pink from paint

			if ( tmp->format->BytesPerPixel == 4 )
			{
				for ( u32 c = 0; c < ( u32 ) ( tmp->w * tmp->h * 4 ); c += 4 )
				{
					pix_data = ( u32 * ) & ( ( u8 * ) tmp->pixels ) [c];

					if ( ( *pix_data & 0x00FFFFFF ) == cl ) {
						*pix_data = 0x00000000;
					}
				}
			}
		}
	}

	return 1;
}

i32 Resman::LoadAnimFromSheet ( string f_name, string res_name, i32 x, i32 y, i32 w, i32 h, i32 frames )
{
	SDL_Surface *temp;
	SDL_Surface *sheet;
	Sprite n_spr;
	i32 hash = HASH ( res_name );

	if ( frames > ANGLES )      // max limit of frames ( 16 ? )
	{
		EXCEX ( 0x05, " Max frame limit exceeded. Fatal." );
	}

	sheet = SDL_LoadBMP ( f_name.c_str() );

	if ( sheet == NULL )
	{
		LOGP2 ( "Error while loading %s", f_name.c_str() );
		EXCEX ( 0x01, "Sprite loading failed !" );
		return ( -1 );
	}

	temp = SDL_DisplayFormat ( sheet );
	SDL_FreeSurface ( sheet );

	if ( temp == NULL )
	{
		LOGP3 ( "Couldn't convert background: %s [%s]", SDL_GetError(), res_name.c_str() );
		EXCEX ( 0x01, "Conversion failed !" );
		return ( -1 );
	}

	if ( x + w * frames  > temp->w )
	{
		LOGP5 ( "Sheet error (W): %d, %d, %d, %d", x, w, frames, temp->w );
		EXCEX ( 0xA1, "FATAL :(" );
	}

	if ( y + h  > temp->h )
	{
		LOGP5 ( "Sheet error (H): %d, %d, %d, %d", y, h, frames, temp->h );
		EXCEX ( 0xA2, "FATAL :(" );
	}

	u32 *pix_data;
	u32 cl = 0x00C9AEFF;        // pink from paint
	n_spr.w = w;
	n_spr.h = h;

	for ( i32 c = 0; c < frames; c++ )
	{
		Frame f;
		SDL_Surface *t_sur = SDL_CreateRGBSurface ( SDL_SWSURFACE | SDL_SRCALPHA, w, h, 32, 0x000000ff,
							 0x0000ff00, 0x00ff0000, 0xff000000 );
//		SDL_FillRect ( t_sur, 0, 0x550000AA );
		SDL_SetAlpha ( t_sur, SDL_SRCALPHA | SDL_SRCCOLORKEY, 0x99 );
		t_sur->format->Amask = 0xFF000000;
		SDL_Rect r;
		r.x = x + w * c;
		r.y = y;
		r.w = w;
		r.h = h;
		SDL_BlitSurface ( temp, &r, t_sur, 0 );

		for ( u32 c = 0; c < ( u32 ) ( w * h * 4 ); c += 4 )
		{
			pix_data = ( u32 * ) & ( ( u8 * ) t_sur->pixels ) [c];

			if ( ( *pix_data & 0x00FFFFFF ) == cl )
			{
				*pix_data = 0x00FF00FF;
			}
		}

		f.surface[0] = t_sur;
		n_spr.frames.push_back ( f );
	}

	SDL_FreeSurface ( temp );
	LOGP3 ( "Sprite [%s] : [%d] loaded...[OK]", f_name.c_str(), hash );
	n_spr.ID = hash;
	Graphics *res_g = new Graphics;
	res_g->hash = hash;
	res_g->org_name = res_name;
	res_g->spr = n_spr;
	_resources.push_back ( res_g );
	return 1;     // number of currently added sprite
}


i32 Resman::Load360Object ( string f_name, string res_name )
{
	LOGP2 ( "Loading rotating object [%s]...", f_name.c_str() );
	LoadStatic ( f_name, res_name );
	Graphics360 *g360 = new Graphics360;
	Graphics *res = ( Graphics * ) GET ( res_name );

	if ( !res )
	{
		EXCEX ( 0xFA, "LoadLiveObject can't find animation in resources" );
	}

	g360->hash = res->hash;
	g360->org_name = res->org_name;
	g360->spr.surface[0] = res->spr.frames[0].surface[0];
	g360->spr.w = res->spr.frames[0].surface[0]->w;
	g360->spr.h = res->spr.frames[0].surface[0]->h;
	SDL_Surface *tmp = res->spr.frames[0].surface[0];
	u32 cl = 0x00FFAEC9;        // pink from paint
	u32 *pix_data;

	for ( u32 c = 0; c < ( u32 ) ( tmp->w * tmp->h * 4 ); c += 4 )
	{
		pix_data = ( u32 * ) & ( ( u8 * ) tmp->pixels ) [c];

		if ( ( *pix_data & 0x00FFFFFF ) == cl )
        {
			*pix_data = 0x00000000;
		}
		else
			*pix_data |= 0xFF000000;

	}

	g360->spr.surface[0]->format->Amask = 0xFF000000;
	SDL_SetAlpha(g360->spr.surface[0], SDL_SRCALPHA | SDL_SRCCOLORKEY,0xFF);

	for ( u32 v = 1; v < 360; v++ )
	{
		tmp = rotozoomSurface ( g360->spr.surface[0], v, 1, 0 );
		g360->spr.surface[v] = tmp;
        tmp->format->Amask = 0xFF000000;

		for ( u32 c = 0; c < ( u32 ) ( tmp->w * tmp->h * 4 ); c += 4 )
		{
			pix_data = ( u32 * ) & ( ( u8 * ) tmp->pixels ) [c];

			if ( ( *pix_data & 0x00FFFFFF ) == cl ) {
					*pix_data = 0xFFAA0000;
			}
		}
	}

	Remove ( res_name );
	_resources.push_back ( g360 );
	return 1;
}

i32 Resman::Remove ( string text )
{
	i32 hash = HASH ( text );

	for ( u32 c = 0; c < _resources.size(); c++ )
	{
		if ( _resources[c]->hash == hash ) {
			_resources.erase ( _resources.begin() + c );
			return 1;
		}
	}

	LOGP2 ( "RESMAN: [REMOVE] No resource named [%s]", text.c_str() );
	return 0;
}
